package top.lishuoboy.jwt.jwt;

import cn.hutool.core.codec.Base64Decoder;
import cn.hutool.core.codec.Base64Encoder;
import cn.hutool.core.map.MapUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.jwt.JWTHeader;
import cn.hutool.jwt.JWTUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.junit.jupiter.api.Test;
import top.lishuoboy.dependency.base.json.HuJsonUtil;

import java.nio.charset.StandardCharsets;
import java.util.TreeMap;

/**
 * JWT 算法原理
 *
 * @author lishuoboy
 * @date 2022/4/18 15:32
 */
public class TestJWT {
    @Test
    public void jwtTest() {

        /**
         jwt官网demo数据。  https://jwt.io/

         1、header
         {
         "alg":"HS256",
         "typ":"JWT"
         }
         2、payload
         {
         "sub": "1234567890",
         "name": "John Doe",
         "iat": 1516239022
         }
         3、VERIFY SIGNATURE
         HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), your-256-bit-secret)
         */
        String header = """
            {"alg":"HS256","typ":"JWT"}""";
        String payload = """
            {"sub":"1234567890","name":"John Doe","iat":1516239022}""";
        String encoded = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";

        // 1、对 header Base64编码
        String base64Header = Base64Encoder.encodeUrlSafe(header);
        // 2、对 payload Base64编码
        String base64Payload = Base64Encoder.encodeUrlSafe(payload);
        // 3、对 header + ．+payload　进行加密 并 Base64编码
        String base64Signature = SecureUtil.hmacSha256("your-256-bit-secret").digestBase64(base64Header + "." + base64Payload, true);
        // 4、拼接为 token
        String token = base64Header + "." + base64Payload + "." + base64Signature;
//        System.out.println(base64Header);
//        System.out.println(base64Payload);
//        System.out.println(base64Signature);
        System.out.println(token);
        System.out.println(token.equals(encoded));

    }

    /** java-jwt */
    @Test
    public void javaJwtTest() {
        String header = """
            {"alg":"HS256","typ":"JWT"}""";
        String payload = """
            {"sub":"1234567890","name":"John Doe","iat":1516239022}""";
        // 测试中发现 header的字段顺序被调换导致生成不同的 encoded
        System.err.println(Base64Decoder.decodeStr("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9"));
        String encoded1 = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
        String encoded2 = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.wrJ__8Q_6BcB2ug9370TBuK5JoAjErqsQtYf7aLcFBk";

        String token = JWT.create().withHeader(MapUtil.builder(new TreeMap<String, Object>()).put("alg", "HS256").put("typ", "JWT").build())
            .withPayload(HuJsonUtil.toMap(payload))
            .sign(Algorithm.HMAC256("your-256-bit-secret".getBytes(StandardCharsets.UTF_8)));
        System.out.println(token);  // eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.wrJ__8Q_6BcB2ug9370TBuK5JoAjErqsQtYf7aLcFBk
        System.out.println(token.equals(encoded1) || token.equals(encoded2));
    }

    /** jjwt */
    @Test
    public void jjwtTest() {

        String header = """
            {"alg":"HS256","typ":"JWT"}""";
        String payload = """
            {"sub":"1234567890","name":"John Doe","iat":1516239022}""";

        // 测试中发现 header的字段顺序被调换导致生成不同的 encoded
        System.err.println(Base64Decoder.decodeStr("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9"));
        String encoded1 = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
        String encoded2 = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.wrJ__8Q_6BcB2ug9370TBuK5JoAjErqsQtYf7aLcFBk";

        String token = Jwts.builder().setHeader(HuJsonUtil.toMap(header)).setPayload(payload).signWith(SignatureAlgorithm.HS256, "your-256-bit-secret".getBytes(StandardCharsets.UTF_8)).compact();
        System.out.println(token);  // eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
        System.out.println(token.equals(encoded1) || token.equals(encoded2));
    }

    /** hutoolJwt */
    @Test
    public void hutoolJwtTest() {
        String header = """
            {"alg":"HS256","typ":"JWT"}""";
        String payload = """
            {"sub":"1234567890","name":"John Doe","iat":1516239022}""";
        // 测试中发现 header的字段顺序被调换导致生成不同的 encoded
        System.err.println(Base64Decoder.decodeStr("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9"));
        String encoded1 = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
        String encoded2 = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.wrJ__8Q_6BcB2ug9370TBuK5JoAjErqsQtYf7aLcFBk";


        String token = JWTUtil.createToken(MapUtil.builder(new TreeMap<String, Object>()).put("alg", "HS256").put("typ", "JWT").build(), HuJsonUtil.toMap(payload), "your-256-bit-secret".getBytes(StandardCharsets.UTF_8));
        System.out.println(token);
        System.out.println(token.equals(encoded1) || token.equals(encoded2));

        String rightToken = encoded2;
        //解析
        cn.hutool.jwt.JWT jwt = JWTUtil.parseToken(rightToken);
        System.out.println(jwt.getHeader(JWTHeader.TYPE));
        System.out.println(jwt.getPayload("sub"));

        //验证
        System.out.println(JWTUtil.verify(token, "your-256-bit-secret".getBytes()));

    }
}
